#  Copyright (c) 1997-2011
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: algebraic_types 10238 2011-05-29 21:51:01Z gawrilow $

declare property_type Vector<Element> : c++ (include => ["polymake/Vector.h"], operators => '@arith:wary | |= @compare:wary') {

   method construct(Int) : c++;

   user_method dim() : c++;

   user_method slice(*) : lvalue_opt : wary : c++;

   user_method slice($$) : lvalue_opt : wary : c++;

   user_method div_exact(*) : lvalue : c++;
}

property_type Vector<Float> {
   
   type()->equal=sub { (typeof Array<Float>)->equal->(@_) };
}

function permuted(Vector, *) : c++;

function permuted_inv(Vector, *) : c++;


# @category Arithmetic

user_function gcd(Vector) : c++;


##################################################################################

declare property_type Matrix<Element, Sym=NonSymmetric> : \
   c++ (name => sub { "Matrix<$_[0]>" }, include => ["polymake/Matrix.h"], operators => '@arith:wary |:wary |=:wary @compare:wary') {

   method construct(Int,Int) : c++;

   method construct(Vector+) {
      my $proto=shift;
      my $M=$proto->construct->(scalar(@_), $_[0]->dim);
      my $i=0;
      $M->[$i++]=$_ for @_;
      $M;
   }

   user_method rows() : c++;

   user_method cols() : c++;

   user_method row($) : lvalue_opt : wary : c++;

   user_method col($) : lvalue_opt : wary : c++;

   user_method minor(*,*) : lvalue_opt : wary : c++;

   method operator($,$) : lvalue_opt : wary : c++;

   user_method diagonal(;$=0) : lvalue_opt : wary : c++;

   user_method anti_diagonal(;$=0) : lvalue_opt : wary : c++;

   user_method div_exact(*) : lvalue : c++;
}

property_type Matrix<Float, NonSymmetric> {

   type()->equal=sub { (typeof Array<Array<Float>>)->equal->(@_) };
}

declare property_type all_rows_or_cols : c++ (name => 'pm::all_selector', include => ["polymake/Matrix.h"], builtin => enum { All });


# @category Data conversion
# Convert to different element type if needed.

user_function convert_to<Element>(Vector) : c++ {
   my $target_type=typeof Element;
   if ($_[0]->type->param==$target_type) {
      $_[0]
   } else {
      # call the C++ converting function
      &{pop(@_)};
   }
}

# @category Data conversion
# Convert to different element type if needed.

user_function convert_to<Element>(Matrix) : c++ {
   my $target_type=typeof Element;
   if ($_[0]->type->param->[0]==$target_type) {
      $_[0]
   } else {
      # call the C++ converting function
      &{pop(@_)};
   }
}

# @category Data conversion

user_function repeat_row(Vector,$) : c++ (include => ["polymake/Matrix.h"]);


# @category Data conversion

user_function vector2row(Vector) : c++ (include => ["polymake/Matrix.h"]);


# @category Data conversion

user_function vector2col(Vector) : c++ (include => ["polymake/Matrix.h"]);


# @category Linear Algebra

user_function diag(Vector) : c++ (include => ["polymake/SparseMatrix.h"]);


# @category Linear Algebra

user_function diag(*,*) : c++ (include => ["polymake/SparseMatrix.h"]);


# @category Linear Algebra

user_function anti_diag(Vector) : c++ (include => ["polymake/SparseMatrix.h"]);


# @category Linear Algebra

user_function anti_diag(*,*) : c++ (include => ["polymake/SparseMatrix.h"]);

user_function rows(Matrix) : c++;

user_function cols(Matrix) : c++;

function permuted_rows(Matrix, *) : c++;

function permuted_inv_rows(Matrix, *) : c++;

function permuted_cols(Matrix, *) : c++;

function permuted_inv_cols(Matrix, *) : c++;


# @category Linear Algebra

user_function transpose(Matrix) : c++ (name => 'T');


# @category Linear Algebra

user_function det(Matrix:wary) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function rank(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function inv(Matrix:wary) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function reduce(Matrix:wary, Vector:wary) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function normalized(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function basis(Matrix) : returns(@) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function basis_affine(Matrix) : returns(@) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function basis_rows(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function basis_cols(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function unit_matrix<Element=Rational>($) : c++ (include => ["polymake/linalg.h"]) {
   if ($_[1] < 0) {
      croak( "unit_matrix - invalid dimension");
   }
   &{pop(@_)}
}

# @category Linear Algebra

user_function unit_vector<Element=Rational>($$) : c++ (include => ["polymake/linalg.h"]) {
   if ($_[1] < 0 || $_[1] >= $_[0]) {
      croak( "unit_vector - invalid dimension or index out of range" );
   }
   &{pop(@_)}
}

# @category Linear Algebra
# Creates a vector with all elements equal to zero.
# @param Int d vector dimension.  If omitted, a vector of dimension 0 is created,
#               which can adjust itself when involved in a block matrix operation.
# @tparam Element type of the vector elements, defaults to [[Rational]].

user_function zero_vector<Element=Rational>(;$=0) : c++ (include => ["polymake/linalg.h"]) {
   if ($_[1] < 0) {
      croak( "zero_vector - invalid dimension");
   }
   &{pop(@_)}
}

# @category Linear Algebra
# Creates a vector with all elements equal to 1.
# @param Int d vector dimension.  If omitted, a vector of dimension 0 is created,
#               which can adjust itself when involved in a block matrix operation.
# @tparam Element type of the vector elements, defaults to [[Rational]].

user_function ones_vector<Element=Rational>(;$=0) : c++ (include => ["polymake/linalg.h"]) {
   if ($_[1] < 0) {
      croak( "ones_vector - invalid dimension");
   }
   &{pop(@_)}
}


# @category Linear Algebra

user_function null_space(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function null_space(Vector) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function lineality_space(Matrix) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function lin_solve(Matrix:wary, Vector:wary) : c++ (include => ["polymake/linalg.h"]);


# @category Linear Algebra

user_function totally_unimodular(Matrix) : c++ (include => ["polymake/totally_unimodular.h"]);

# @category Linear Algebra
# Check whether both matrices are bases of the same linear subspace.

user_function equal_bases(Matrix, Matrix) {
   my ($M1, $M2)=@_;
   return $M1->rows==$M2->rows && !(null_space($M1) * transpose($M2));
}

user_function dense(Vector) { shift }

user_function dense(Matrix) { shift }


# @category Combinatorics

user_function permutation_matrix(*) : c++ (include => ["polymake/permutations.h"]);

##################################################################################

declare property_type SparseIterator<*> : Iterator : c++ {

   method index() : c++;
}

declare property_type SparseVector<Element> : Vector<Element> : c++ (include => ["polymake/SparseVector.h"]) {

   user_method size() : c++;
}

declare property_type SparseMatrix<Element, Sym=NonSymmetric> : Matrix<Element,Sym> : c++ (include => ["polymake/SparseMatrix.h"]) {

   user_method squeeze() : non_const : void : c++;

   user_method squeeze_rows() : non_const : void : c++;

   user_method squeeze_cols() : non_const : void : c++;
}

function entire(SparseVector) : c++ : returns(SparseIterator<*>);

# @category Data conversion
# Convert to an equivalent dense vector of the same element type
# @param SparseVector v
user_function dense<Element>(SparseVector<Element>) { new Vector<Element>(shift) }

# @category Data conversion
# Convert to an equivalent dense matrix of the same element type
# @param SparseMatrix m
user_function dense<Element>(SparseMatrix<Element>) { new Matrix<Element>(shift) }


# @category Data conversion

user_function toVector<Scalar>(Set:wary $) : c++ (name => 'same_element_sparse_vector', include => ["polymake/SparseVector.h"]);


# @category Data conversion

user_function toMatrix<Scalar>(IncidenceMatrix) : c++ (name => 'same_element_sparse_matrix', include => ["polymake/SparseMatrix.h"]);

# @category Data conversion
# Convert to a dense 0/1 matrix
# @param IncidenceMatrix m
user_function dense(IncidenceMatrix) { dense(toMatrix<Int>(@_)); }

# @category Data conversion
# Convert to a dense 0/1 vector of a given dimension
# @param Set s
# @param Int dim
user_function dense(Set $) { dense(toVector<Int>(@_)); }

# @category Data conversion
# Get the positions of non-zero entries of a sparse vector.
# @param SparseVector v
# @return Set<Int>
user_function indices(SparseVector) : c++ (include => ["polymake/Set.h"]);


# @category Data conversion
# Get the positions of non-zero entries of a sparse matrix.
# @param SparseMatrix m
# @return IncidenceMatrix
user_function index_matrix(SparseMatrix) : c++ (include => ["polymake/IncidenceMatrix.h"]);


##################################################################################

##declare property_type MaxPlusRational : c++ (operators => ' bool @arith @compare') {

##   function ONE() : c++ (name => 'MaxPlusRational::ONE', include => ["MaxPlusRational.h"]);

##   function ZERO() : c++ (name => 'MaxPlusRational::ZERO', include => ["MaxPlusRational.h"]);
   
##   user_method get_value() : c++;
##}

##user_function isfinite(MaxPlusRational) : c++ (include => ["MaxPlusRational.h"]);

##user_function isinf(MaxPlusRational) : c++ (include => ["MaxPlusRational.h"]);

##################################################################################

declare property_type Ring<Coefficient=Rational, Exponent=Int> : c++ \
   (include => ["polymake/Ring.h"], operators => '== !=', default_constructor => 0) {

   # either a number of variables, a single name, or a list of names given per reference
   method construct(*) : c++;

   # number of variables and the name stem
   method construct(Int,$) : c++;

   # list of names
   method construct($$@) {
      (shift)->construct->(\@_);
   }

   user_method variables() : returns(@) : c++ (include => ["polymake/Polynomial.h"]);

   user_method variable() : c++ (include => ["polymake/Polynomial.h"]);

   user_method names() : c++;

   method id() : c++;
}

declare property_type Monomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv ^ ^= @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(Vector,Ring) : c++;
}

declare property_type UniMonomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv ^ ^= @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;
}

declare property_type Term<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(Vector,*,Ring) : c++;
}

declare property_type UniTerm<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;
}

declare property_type Polynomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;

   method construct(Matrix,*,Ring) : c++;

   user_method lm_exp() : c++;

   user_method lc() : c++;
}

declare property_type UniPolynomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["polymake/Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;

   method construct(*,*,Ring) : c++;

   user_method lm_exp() : c++;

   user_method lc() : c++;
}



# Local Variables:
# mode: perl
# cperl-indent-level: 3
# indent-tabs-mode:nil
# End:
